package com.pwser.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.pwser.constant.ConstantKey;
import com.pwser.handler.MyAuthenticationFailureHandler;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

/**
 * 验证用户名密码正确后，生成一个token，并将token返回给客户端
 * 该类继承自UsernamePasswordAuthenticationFilter，重写了其中的3个方法 
 * attemptAuthentication ：接收并解析用户凭证。
 * successfulAuthentication ：用户成功登录后，这个方法会被调用，我们在这个方法里生成token。
 * unsuccessfulAuthentication : 登录失败后调用方法，调用登录异常的handler
 */
public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter {

	private AuthenticationManager authenticationManager;

	public JWTLoginFilter(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}

	// 接收并解析用户凭证
	@Override
	public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
			throws AuthenticationException {
		String loginAccount = req.getParameter("login_account").toString();
		String loginPass = req.getParameter("login_pass").toString();
		return authenticationManager
				.authenticate(new UsernamePasswordAuthenticationToken(loginAccount, loginPass, new ArrayList<>()));
	}

	// 登录失败后调用方法
	@Override
	protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException failed) throws IOException, ServletException {
		this.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
		super.unsuccessfulAuthentication(request, response, failed);
	}

	// 用户成功登录后，这个方法会被调用，我们在这个方法里生成token
	@Override
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
			Authentication auth) throws IOException, ServletException {
		// builder the token
		String token = null;
		try {
			Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
			// 定义存放角色集合的对象
			List roleList = new ArrayList<>();
			for (GrantedAuthority grantedAuthority : authorities) {
				roleList.add(grantedAuthority.getAuthority());
			}
			// 设置过期时间
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(new Date());
			calendar.add(Calendar.SECOND, 60);
			Date time = calendar.getTime();
			token = Jwts.builder().setSubject(auth.getName() + "-" + roleList).setExpiration(time) // 设置过期时间30天
					.signWith(SignatureAlgorithm.HS512, ConstantKey.SIGNING_KEY) // 采用什么算法是可以自己选择的，不一定非要采用HS512
					.compact();
			// 登录成功后，返回token储存到cookie里面
			// response.setHeader("Authorization", "token:" + token);
			Cookie cookie = new Cookie("Authorization", "token:" + token);
			cookie.setMaxAge(3600 * 24 * (ConstantKey.TIME_VALIDITY));// 设置其生命周期30天
			response.addCookie(cookie);
			response.sendRedirect(request.getContextPath() + "/main.html");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
